package code

import (
	"container/list"
	"fmt"
	utils "gitee.com/ichub/goconfig/common/base/baseutils/stringutils"
	"gitee.com/ichub/gofactroy/common/ichubbase"
	"gitee.com/ichub/gofactroy/factroy/buildfactroy/rpc"
	"gitee.com/ichub/gofactroy/factroy/dbfactroy"
	"strings"
	"time"
)

type ModelFactroy struct {
	rpcfactroy rpc.RpcFactroy
}

func (model *ModelFactroy) makeModelIniLst(columns *[]dbfactroy.COLUMNS, pkey string, iniNil bool) *list.List {

	s := `
	//entity.{{.colname}} = new({{.goType}})
	`
	if iniNil {
		s = `
		//if entity.{{.colname}} == nil {
			//entity.{{.colname}} = new({{.goType}})
		//}
	`
	}
	lst := list.New()
	for _, v := range *columns {
		colname := utils.Case2Camel(v.COLUMN_NAME)

		goType := v.FindGoType(v.DATA_TYPE)
		if goType == "" {
			goType = "string"
		}

		if v.COLUMN_NAME != pkey {

			vars := make(map[string]interface{})
			vars["goType"] = goType
			vars["colname"] = colname
			lst.PushBack(utils.ParseTemplateString(s, vars))
		}

	}

	utils.LogList(lst)
	return lst
}

func (model *ModelFactroy) buildComment(table string, columns *[]dbfactroy.COLUMNS) *[]string {
	var rets []string
	for _, v := range *columns {
		s := fmt.Sprintf(`comment on column %s.%s is '%s';`, table, v.COLUMN_NAME, v.COLUMN_COMMENT)
		rets = append(rets, s)
	}
	return &rets
}

func (model *ModelFactroy) makeM2PLst(columns *[]dbfactroy.COLUMNS) *list.List {

	s := `{{.Tab}}cpentity.{{.colname}} =  *entity.{{.colname}}`

	lst := list.New()
	for _, v := range *columns {
		colname := utils.Case2Camel(v.COLUMN_NAME)
		//goType := dbtool.FindGoType(v.DATA_TYPE)
		vars := make(map[string]interface{})
		vars["colname"] = colname
		vars["Tab"] = fmt.Sprintf("\t\t")
		lst.PushBack(utils.ParseTemplateString(s, vars))
	}

	utils.PrintList(lst)
	return lst
}
func (model *ModelFactroy) makeM2MLst(tableTool *dbfactroy.DbFactroy, columns *[]dbfactroy.COLUMNS) *list.List {

	s := `{{.Tab}}entity.{{.colname}} =  cpentity.{{.colname}}`

	lst := list.New()
	for _, v := range *columns {
		if tableTool.Pkey == v.COLUMN_NAME {
			continue
		}
		colname := utils.Case2Camel(v.COLUMN_NAME)
		vars := make(map[string]interface{})
		vars["Tab"] = fmt.Sprintf("\t\t")
		vars["colname"] = colname
		lst.PushBack(utils.ParseTemplateString(s, vars))
	}

	utils.LogList(lst)
	return lst
}
func (model *ModelFactroy) makeM2MNotNilLst(tableTool *dbfactroy.DbFactroy, columns *[]dbfactroy.COLUMNS) *list.List {

	s := `{{.Tab}}entity.{{.colname}} = cpentity.{{.colname}}`

	lst := list.New()
	for _, v := range *columns {
		if tableTool.Pkey == v.COLUMN_NAME {
			continue
		}
		colname := utils.Case2Camel(v.COLUMN_NAME)
		vars := make(map[string]interface{})
		vars["Tab"] = fmt.Sprintf("\t\t")
		vars["colname"] = colname
		lst.PushBack(utils.ParseTemplateString(s, vars))
	}

	utils.LogList(lst)
	return lst
}

func (model *ModelFactroy) buildGetSet(cs *dbfactroy.COLUMNS) string {
	s := `
	func (entity *{{.Model}}) Get{{.FieldName}}() {{.goType}} {
		 
		return  entity.{{.FieldName}}		
		
	}

	func (entity *{{.Model}}) Set{{.FieldName}}({{.FieldName}} {{.goType}}) {
		entity.{{.FieldName}}= {{.FieldName}}
	}

`
	vars := make(map[string]interface{})

	t := utils.UcfirstCase2Camel(cs.TableName)
	vars["Model"] = t
	vars["FieldName"] = utils.Case2Camel(cs.COLUMN_NAME)
	vars["goType"] = cs.FindGoType(cs.DATA_TYPE)
	vars["ReturnValue"] = cs.ReturnValue()

	return utils.ParseTemplateString(s, vars)
}

func (model *ModelFactroy) buildGetSets(cs *[]dbfactroy.COLUMNS) string {
	var r []string
	for _, v := range *cs {
		r = append(r, model.buildGetSet(&v))
	}
	return strings.Join(r, "\n")

}

func (model *ModelFactroy) buildModel(tableTool *dbfactroy.DbFactroy,
	columns *[]dbfactroy.COLUMNS,
	ms *list.List,
	msdto *list.List) string {
	bs := dbfactroy.InstFileFactroy.ReadTemplateModel()

	vars := make(map[string]interface{})

	vars["FileName"] = utils.Case2Camel(tableTool.Table) + ".go"
	vars["Description"] = "实体" + utils.Case2Camel(tableTool.Table) + ""
	vars["Author"] = tableTool.Author
	vars["DATETIME"] = time.Now().Format(ichubbase.FormatDateTime)

	vars["Model"] = utils.Case2Camel(tableTool.Table)
	vars["ModelDefine"] = utils.List2string(ms)
	vars["ModelDefineDto"] = utils.List2string(msdto)

	vars["Pkey"] = utils.Case2Camel(tableTool.Pkey)
	vars["PkeyType"] = tableTool.FindGoType(tableTool.PkeyType)
	vars["PkeyValue"] = "0"
	vars["fmtType"] = "%d"
	if tableTool.FindGoType(tableTool.PkeyType) == "string" {
		vars["PkeyValue"] = "\"\""
		vars["fmtType"] = "%s"
	}

	vars["Table"] = tableTool.Table
	vars["TableComment"] = tableTool.TableComment

	vars["IfComment"] = "//"
	vars["sql"] = "``"
	if !tableTool.Dbtype_mysql {
		vars["IfComment"] = ""
		vars["sql"] = "`" + strings.Join(*model.buildComment(tableTool.Table, columns), "\n\t\t") + "`"
	}

	vars["Model2PbMsg"] = utils.List2string(model.rpcfactroy.Model2PbMsg(columns))
	vars["PbMsg2Model"] = utils.List2string(model.rpcfactroy.PbMsg2Model(columns))
	vars["IniPbMsg"] = utils.List2string(model.rpcfactroy.IniPbMsg(columns))

	vars["copy"] = utils.List2string(model.makeM2MLst(tableTool, columns))
	vars["copyNotNil"] = utils.List2string(model.makeM2MNotNilLst(tableTool, columns))

	iniList := model.makeModelIniLst(columns, tableTool.Pkey, false)
	iniNilList := model.makeModelIniLst(columns, tableTool.Pkey, true)
	vars["iniFields"] = utils.List2stringBy(iniList, "\t\t")
	vars["iniNilFields"] = utils.List2stringBy(iniNilList, "\t\t")

	vars["buildGetSets"] = model.buildGetSets(columns)

	return utils.ParseTemplateString(string(bs), vars)

}

func (model *ModelFactroy) buildModelFile(dbt *dbfactroy.DbFactroy,
	cs *[]dbfactroy.COLUMNS, ms *list.List, msdto *list.List) (dir, f, c string) {

	fbase := utils.Lcfirst(utils.Case2Camel(dbt.Table))
	dir = dbfactroy.InstFileFactroy.TransDir(dbfactroy.Gendir_model, fbase)

	f, c = fbase+".go", model.buildModel(dbt, cs, ms, msdto)
	dbfactroy.InstFileFactroy.WriteFileModule(dir, f, c)

	return
}

func (model *ModelFactroy) buildProtoFile(tool *dbfactroy.DbFactroy, ps *list.List) (dir, f, c string) {

	fbase := utils.Lcfirst(utils.Case2Camel(tool.Table))
	dir = dbfactroy.InstFileFactroy.TransDir(dbfactroy.Gendir_proto, fbase)

	f, c = fbase+"Proto.proto", model.buildProto(tool, ps)
	dbfactroy.InstFileFactroy.WriteFileModule(dir, f, c)
	dbfactroy.InstFileFactroy.WriteFileModule(dbfactroy.Gendir_PBTool, f, c)

	return
}

// ReadTemplateServiceInterface
func (model *ModelFactroy) buildProto(tableTool *dbfactroy.DbFactroy, ps *list.List) string {

	b := dbfactroy.InstFileFactroy.ReadTemplateProto()
	vars := make(map[string]interface{})
	vars["Module"] = utils.Case2Camel(tableTool.Table)
	vars["LcModule"] = strings.ToLower(utils.Case2Camel(tableTool.Table))
	vars["ModuleMessage"] = utils.List2stringBy(ps, "\n\t")
	vars["pkey"] = utils.Lcfirst(utils.Case2Camel(tableTool.Pkey))
	vars["pkeyType"] = tableTool.FindProtoType(tableTool.PkeyType)

	return utils.ParseTemplateString(string(b), vars)

}

func (model *ModelFactroy) Build(tool *dbfactroy.DbFactroy) (dir, f, c string) {

	cs, ms, ps, msdto := tool.BuildModel()
	dir, f, c = model.buildProtoFile(tool, ps)
	dir, f, c = model.buildModelFile(tool, cs, ms, msdto)

	return
}
